package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.Room;
import com.myk.game.gobangchess.Sign;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.signs.*;
import com.myk.game.gobangchess.utils.GridsUtils;
import com.myk.game.gobangchess.utils.Pair;

import java.util.*;

/**
 * 禽将棋
 */
public class ToriShogiRoom extends Room {

    private CacheSign cacheSign; //缓存标记
    private static int BLACK_SLOT_ROW; //黑方棋槽所在行
    private static int WHITE_SLOT_ROW; //白方棋槽所在行
    private static int BLACK_CAMP_ROW; //黑方阵线
    private static int WHITE_CAMP_ROW; //白方阵线
    private List<Chess> chessList; //场上棋子集合
    private Komadai blackKomadai; //黑方拘台
    private Komadai whiteKomadai; //白方拘台
    private Chess choose; //当前选中的棋子
    private Chess select; //当前选中的俘虏
    private GroundSign dropTip;//打入坐标提示
    private LineSign moveTip;//移动箭头提示

    public ToriShogiRoom(String roomName) {
        super(roomName, "十八世纪时,将棋九世名人大桥宗英发明的日本将棋变体。", "禽将棋", GridsUtils.createEmptyGrids(9, 9), true, false);
        initChessBoardStyle();
    }

    //初始化背景样式
    private void initChessBoardStyle() {
        BLACK_SLOT_ROW = 0;
        WHITE_SLOT_ROW = 8;
        BLACK_CAMP_ROW = 2;
        WHITE_CAMP_ROW = 6;

        List<Sign> chessboardStyle = new ArrayList<>();
        int row = curGrids.length;
        int col = curGrids[0].length;

        //将画布默认格子隐藏了
        chessboardStyle.add(new GroundSign(getIndex(0, 0), getIndex(row - 1, col - 1), ColorCost.TABLECLOTH_COLOR, ColorCost.TABLECLOTH_COLOR, 2.0f, 0, 0));

        //画棕棋盘颜色
        chessboardStyle.add(new GroundSign(getIndex(BLACK_SLOT_ROW + 1, 1), getIndex(WHITE_SLOT_ROW - 1, col - 2), "#FFDEB582", "#00000000", 1.0f, 0, 0));

        //绘制格子线
        for (int i = 1; i < row; i++) {
            List<Pair<Integer, Integer>> nodes1 = new ArrayList<>();
            nodes1.add(new Pair<>(getIndex(i, 1), 0)); //起点
            nodes1.add(new Pair<>(getIndex(i, col - 2), 2)); //终点
            chessboardStyle.add(new PathSign(nodes1, "#FF333333", "#00000000", 0.5f, 0));
        }
        for (int j = 1; j < col; j++) {
            List<Pair<Integer, Integer>> nodes1 = new ArrayList<>();
            nodes1.add(new Pair<>(getIndex(1, j), 0)); //起点
            nodes1.add(new Pair<>(getIndex(row - 2, j), 6)); //终点
            chessboardStyle.add(new PathSign(nodes1, "#FF333333", "#00000000", 0.5f, 0));
        }

        //画定位点
        FigureSign figure = FigureSign.makeGroundFigure(getIndex(3, 3), getIndex(5, 5), "#FF000000");
        figure.setCompPoint(1, 0, 1, 0, 1, 0, 1, 0, 0);
        chessboardStyle.add(figure);

        //画棋盘外边框
        List<Pair<Integer, Integer>> nodes1 = new ArrayList<>();
        nodes1.add(new Pair<>(getIndex(1, 1), 0));
        nodes1.add(new Pair<>(getIndex(1, col - 2), 2));
        nodes1.add(new Pair<>(getIndex(row - 2, col - 2), 8));
        nodes1.add(new Pair<>(getIndex(row - 2, 1), 6));
        nodes1.add(new Pair<>(getIndex(1, 1), 0));
        nodes1.add(new Pair<>(getIndex(1, col - 2), 2));
        chessboardStyle.add(new PathSign(nodes1, "#FF333333", "#00000000", 3.2f, 0));
        chessboardStyle.add(new PathSign(nodes1, "#FFB0896F", "#00000000", 2.2f, 0));

        //添加到缓存标记中
        cacheSign = new CacheSign(this, "background", 1, true, chessboardStyle); //*** 修改背景样式记得改这里的版本号！！！
    }

    @Override
    public String getRuleText() {
        return "《禽将棋》\n" +
                "基本规则：" +
                "1、7×7格的将棋盘，接近自己的二行横列为自阵，反之，接近对手的二行横列为敌阵。\n" +
                "2、棋子共六类，若包含升级棋则八种，各方有十六颗棋子。\n" +
                "3、只有鹰与燕有升级棋，进入敌阵、在敌阵中移动或从敌阵出来都会立即升变，且升变为强制性。棋子刚打入敌阵时不立即升变，要再走一步才升变。\n" +
                "4、有打入与持驹规则。\n" +
                "5、燕的打入类同于步兵，不可打步诘，但可将燕打入于已有己方燕一子的一路，但不可打入己方燕已有两子以上的一路。\n" +
                "6、不可打入无去向位置（与将棋相同）。" +
                "7、棋子被俘虏后变回前身棋。\n" +
                "8、将对方的鹏捕获为胜。\n" +
                "9、循环局面出现三次，先开始循环周期的玩家必须改变行动，否则判负。\n" +
                "棋子走法：" +
                "前身棋:鹏  等同于玉将，可循八方走一格。若被捕获则输掉游戏。\n" +
                "前身棋:鹤  走法如同于猛豹，可循纵向、斜向走一格。\n" +
                "前身棋:雉  可循前向越入第二格，或循后斜向走一格。\n" +
                "前身棋:鹑  鹑依据配置于左右两侧而走法不同，棋上会标明左或右字。\n" +
                "         左鹑可以向前或右后斜自由行走，或循左后斜向走一格。\n" +
                "         右鹑可以向前或左后斜自由行走，或循右后斜向走一格。\n" +
                "前身棋:鹰  可循后方以外的方向走一格。\n" +
                "升级棋:雕  是鹰的升级。除保留原本走法外，可以向前斜或后方自由行走，或循后斜走最多两格。\n" +
                "前身棋:燕  可循前走一格。\n" +
                "升级棋:雁  可循前斜向越两格，或循后向越两格。";
    }

    @Override
    public String getCoordMode() {
        return "03501111";
    }

    @Override
    public CacheSign getCacheSignByName(String cacheName) {
        return cacheSign;
    }

    @Override
    public String getGameInfo() {
        //先全部初始化
        curGrids = GridsUtils.copyGrids(originGrids);
        signList.clear();
        signList.add(cacheSign);

        //根据chessList集合和choose对象来生成要显示到客户端的布局和标记
        if (chessList != null && chessList.size() > 0) {
            //绘制棋子
            for (Chess chess : chessList) {
                //棋子自身形象在内部绘制
                chess.drawSelf(this);
                //表示方向的小箭头则在外部绘制
                if (chess.side == 1) {
                    signList.add(new TitleSign((chess.col + 0.5f) / curGrids[0].length, (chess.row + 0.785f) / curGrids.length, 0, "▼", "#FF111111", 0.1f));
                }
                else {
                    signList.add(new TitleSign((chess.col + 0.5f) / curGrids[0].length, (chess.row + 0.215f) / curGrids.length, 0, "▲", "#FFEEEEEE", 0.1f));
                }
            }
            //绘制拘台
            if (blackKomadai != null && whiteKomadai != null) {
                blackKomadai.drawSelf(this);
                whiteKomadai.drawSelf(this);
            }
            //绘制打入坐标框框
            if (dropTip != null) {
                signList.add(dropTip);
            }
            //绘制主动移动箭头
            if (moveTip != null) {
                signList.add(moveTip);
            }
            //绘制对弈时的选中棋子移动状态
            if (choose != null) {
                choose.drawCanMovedPath(this); //绘制棋子可移动路径
            }
            //绘制对弈时选中的俘虏可打入路径
            if (select != null) {
                select.drawCanDropPos(this); //绘制俘虏可打入的位置
            }
        }
        return super.getGameInfo();
    }

    @Override
    protected void onStartPrepare() {
        initChessList(); //重新创建初始布局的棋子们
        //testChessList(); // 构建测试布局
    }

    private void initChessList() {
        chessList = new ArrayList<>();
        blackKomadai = new Komadai(1, this);
        whiteKomadai = new Komadai(2, this);

        chessList.add(new RightQuail(1, 1, 1));
        chessList.add(new Pheasant(1, 1, 2));
        chessList.add(new Crane(1, 1, 3));
        chessList.add(new Phoenix(1, 1, 4));
        chessList.add(new Crane(1, 1, 5));
        chessList.add(new Pheasant(1, 1, 6));
        chessList.add(new LeftQuail(1, 1, 7));
        chessList.add(new Falcon(1, 2, 4));
        chessList.add(new Swallow(1, 3, 1));
        chessList.add(new Swallow(1, 3, 2));
        chessList.add(new Swallow(1, 3, 3));
        chessList.add(new Swallow(1, 3, 4));
        chessList.add(new Swallow(1, 3, 5));
        chessList.add(new Swallow(1, 3, 6));
        chessList.add(new Swallow(1, 3, 7));
        chessList.add(new Swallow(1, 4, 3));

        chessList.add(new LeftQuail(2, 7, 1));
        chessList.add(new Pheasant(2, 7, 2));
        chessList.add(new Crane(2, 7, 3));
        chessList.add(new Phoenix(2, 7, 4));
        chessList.add(new Crane(2, 7, 5));
        chessList.add(new Pheasant(2, 7, 6));
        chessList.add(new RightQuail(2, 7, 7));
        chessList.add(new Falcon(2, 6, 4));
        chessList.add(new Swallow(2, 5, 1));
        chessList.add(new Swallow(2, 5, 2));
        chessList.add(new Swallow(2, 5, 3));
        chessList.add(new Swallow(2, 5, 4));
        chessList.add(new Swallow(2, 5, 5));
        chessList.add(new Swallow(2, 5, 6));
        chessList.add(new Swallow(2, 5, 7));
        chessList.add(new Swallow(2, 4, 5));

        noticeBlackMove();
    }

    private void testChessList() {
        resetGrids();
        chessList = new ArrayList<>();
        blackKomadai = new Komadai(1, this);
        whiteKomadai = new Komadai(2, this);

//        chessList.add(new Eagle(1, 2, 3));
//        chessList.add(new Eagle(1, 4, 5));

        noticeBlackMove();
        //noticeWhiteMove();
    }

    @Override
    public void resetGrids() {
        super.resetGrids();
        chessList = null;
        blackKomadai = null;
        whiteKomadai = null;
        choose = null;
        select = null;
        dropTip = null;
        moveTip = null;
    }

    @Override
    public void doRule(int row, int col, int value) {
        boolean isFightArea = isFightArea(row, col); //判断点击的是棋盘还是拘台
        boolean isChooseOrSelect = choose != null || select != null; //判断是否选定了要移动或打入的棋子
        //无选中等待选棋时
        if (!isChooseOrSelect) {
            if (isFightArea) {
                //选择场上棋子
                Chess chess = getChessByPos(row, col);
                if (chess != null && chess.side == value) {
                    chooseChess(chess);
                    noticeAllRefreshGameInfo();
                }
            }
            else {
                //选择己方拘台俘虏
                Chess captive = getCaptiveByPos(row, col);
                if (captive != null) {
                    selectCaptive(captive);
                    noticeAllRefreshGameInfo();
                }
            }
        }
        //有选中等待落子时
        else {
            if (isFightArea) {
                //选中场上棋子等待移动时
                if (choose != null) {
                    if (choose.isPosCanMove(row, col, this)) {
                        moveChess(row, col, choose); //移动棋子
                        checkOver(value); //检查胜负
                    }
                    else {
                        clearChooseSelect();
                        noticeAllRefreshGameInfo();
                    }
                }
                //选中拘台俘虏准备打入时
                else {
                    if (select.isPosCanDrop(row, col, this)) {
                        dropChess(row, col, select); //打入棋子
                        checkOver(value); //检查胜负
                    }
                    else {
                        clearChooseSelect();
                        noticeAllRefreshGameInfo();
                    }
                }
            }
            else {
                clearChooseSelect();
                noticeAllRefreshGameInfo();
            }
        }
    }

    /**
     * 移动棋子
     */
    private void moveChess(int row, int col, Chess chess) {
        dropTip = null;
        moveTip = new LineSign(getIndex(chess.row, chess.col), getIndex(row, col), ColorCost.MOVE_ARROW_LIGHT, 1); //添加移动箭头提示
        Chess enemyChess = getChessByPos(row, col);
        if (enemyChess != null) {
            captureChess(enemyChess); //俘虏敌方棋子
        }
        chess.checkUpgrade(); //从敌阵出来也会升变所以这里也要判断一下
        chess.row = row;
        chess.col = col;
        chess.selected = false;
        chess.checkUpgrade(); //进入敌阵或在敌阵移动都会升变
        choose = null;
    }

    /**
     * 捕获棋子
     */
    private void captureChess(Chess enemyChess) {
        if (enemyChess.side == 1) { //黑棋被俘虏
            chessList.remove(enemyChess);
            whiteKomadai.addChess(enemyChess);
            enemyChess.side = 2;
        }
        else { //白棋被俘虏
            chessList.remove(enemyChess);
            blackKomadai.addChess(enemyChess);
            enemyChess.side = 1;
        }
    }

    /**
     * 选中俘虏
     */
    private void selectCaptive(Chess captive) {
        if (select != null) select.selected = false;
        select = captive;
        select.selected = true;
    }

    /**
     * 打入棋子
     */
    private void dropChess(int row, int col, Chess captureChess) {
        moveTip = null;
        dropTip = new GroundSign(getIndex(row, col), ColorCost.TRANSPARENT, ColorCost.NEW_PUT_POINT_LIGHT, 1.0f, 1, 0); //添加打入点提示
        if (cur == 1) {
            blackKomadai.removeChess(captureChess);
        }
        else {
            whiteKomadai.removeChess(captureChess);
        }
        captureChess.side = cur;
        captureChess.row = row;
        captureChess.col = col;
        captureChess.selected = false;
        chessList.add(captureChess);
        select = null;
    }

    /**
     * 选中棋子
     */
    private void chooseChess(Chess chess) {
        if (choose != null) choose.selected = false;
        choose = chess;
        choose.selected = true;
    }

    /**
     * 取消各种选中状态
     */
    private void clearChooseSelect() {
        if (choose != null) {
            choose.selected = false;
            choose = null;
        }
        if (select != null) {
            select.selected = false;
            select = null;
        }
    }

    /**
     * 判断游戏是否结束
     */
    private void checkOver(int curIsBlack) {
        stepAdd(); //增加回合计数
        if (blackKomadai.captiveMap.containsKey(Phoenix.ORIGIN_TYPE)) {
            gameTip = "白方[鵬]被俘虏，黑方获胜！";
            doOver(WinMode.BLACK_WIN, "白方[鵬]被俘虏，黑方获胜！");
        }
        else if (whiteKomadai.captiveMap.containsKey(Phoenix.ORIGIN_TYPE)) {
            gameTip = "黑方[鵬]被俘虏，白方获胜！";
            doOver(WinMode.WHITE_WIN, "黑方[鵬]被俘虏，白方获胜！");
        }
        else {
            int loopTime = calculateLoopTime(); //计算循环次数
            //没有结束切换行动方
            if (curIsBlack == 1) {
                if (loopTime > 3) { //循环次数超过3次，判负
                    gameTip = "黑方循环行动超过三次，白方获胜！";
                    doOver(WinMode.WHITE_WIN, "黑方循环超过三次，白方获胜！");
                }
                else if (loopTime == 3) { //循环次数达到三次，提示必须变招
                    gameTip = "行动循环已达三次，白方必须变招，否则将会判负！";
                    noticeWhiteMove();
                }
                else {
                    gameTip = "-1";
                    noticeWhiteMove();
                }
            }
            else {
                if (loopTime > 3) {
                    gameTip = "白方循环行动超过三次，黑方获胜！";
                    doOver(WinMode.BLACK_WIN, "白方循环行动超过三次，黑方获胜！");
                }
                else if (loopTime > 2) {
                    gameTip = "行动循环已达三次，黑方必须变招，否则将会判负！";
                    noticeBlackMove();
                }
                else {
                    gameTip = "-1";
                    noticeBlackMove();
                }
            }
        }
    }

    /**
     * 计算循环局面的次数
     */
    private int calculateLoopTime() {
        //++根据chessList中所有棋子数量和横纵坐标是否升变判断发生循环的次数
        return 0;
    }

    /**
     * 判断坐标是否在对战区域
     * 棋盘对战区域是在整个9x9的二维数组中间7x7之中。
     */
    private boolean isFightArea(int row, int col) {
        return row >= 1 && row <= curGrids.length - 2 && col >= 1 && col <= curGrids[0].length - 2;
    }

    /**
     * 根据坐标搜索棋子
     */
    private Chess getChessByPos(int row, int col) {
        for (Chess chess : chessList) {
            if (chess.row == row && chess.col == col) {
                return chess;
            }
        }
        return null;
    }

    /**
     * 根据坐标搜索俘虏棋子
     */
    private Chess getCaptiveByPos(int row, int col) {
        if (this.cur == 1) {
            return blackKomadai.getChessByPos(getIndex(row, col));
        }
        else {
            return whiteKomadai.getChessByPos(getIndex(row, col));
        }
    }

    /**
     * 拘台
     * （黑方拘台所包含的棋子都是白方棋子，白方拘台所有包含的棋子都是黑方棋子）
     */
    private static class Komadai {

        private final int[] SLOT_INDEXES; //棋槽对应游戏网格界面的坐标
        private final String[] slotHeads; //每个棋槽的棋头排序，存放棋子的originType,可知最多7种  燕(雁)，鹤，雉，左鹑，右鹑，鹰(雕)，鹏
        private final int side; //拘台阵营，1：黑方，2：白方
        private final Map<String, List<Chess>> captiveMap; //被俘虏棋子容器

        public Komadai(int side, ToriShogiRoom room) {
            if (side == 1) {
                //黑方拘台棋槽坐标 （顶部从左往右）
                SLOT_INDEXES = new int[]{
                        room.getIndex(0, 0),
                        room.getIndex(0, 1),
                        room.getIndex(0, 2),
                        room.getIndex(0, 3),
                        room.getIndex(0, 4),
                        room.getIndex(0, 5),
                        room.getIndex(0, 6)
                };
            }
            else {
                //白方拘台棋槽坐标 （底部从右往左）
                SLOT_INDEXES = new int[]{
                        room.getIndex(8, 8),
                        room.getIndex(8, 7),
                        room.getIndex(8, 6),
                        room.getIndex(8, 5),
                        room.getIndex(8, 4),
                        room.getIndex(8, 3),
                        room.getIndex(8, 2)
                };
            }
            slotHeads = new String[7];
            this.side = side;
            this.captiveMap = new HashMap<>();
        }

        /**
         * 添加被俘虏的棋子
         */
        public void addChess(Chess chess) {
            chess.upgrade = false; //棋子被俘虏蜕回前身棋
            String type = chess.getOriginType();
            for (int i = 0; i < slotHeads.length; i++) {
                if (slotHeads[i] == null) { //按照顺序添加，遇到空位就初始添加整个头部索引和集合容器
                    slotHeads[i] = type;
                    List<Chess> chessArray = new ArrayList<>();
                    chessArray.add(chess);
                    captiveMap.put(type, chessArray);
                    break;
                }
                else if (slotHeads[i].equals(type)) { //找到自己所在的集合
                    captiveMap.get(type).add(chess);
                    break;
                }
            }
        }

        /**
         * 从拘台中拿走棋子
         */
        public void removeChess(Chess chess) {
            //移除被俘虏棋子，外部保证改棋子肯定在拘台的集合中
            List<Chess> list = captiveMap.get(chess.getOriginType());
            list.remove(chess);
            //如果某种棋子数量为0了，移除集合容器，还要移除棋头，然后棋头数组还要往前挪动
            if (list.size() == 0) {
                captiveMap.remove(chess.getOriginType());
                boolean flag = false;
                for (int i = 0; i < slotHeads.length; i++) {
                    if (flag) {
                        slotHeads[i - 1] = slotHeads[i];
                    }
                    else if (slotHeads[i].equals(chess.getOriginType())) {
                        slotHeads[i] = null;
                        flag = true;
                    }
                }
            }
        }

        /**
         * 根据坐标查询俘虏棋子
         */
        public Chess getChessByPos(int index) {
            for (int i = 0; i < SLOT_INDEXES.length; i++) {
                if (SLOT_INDEXES[i] == index) { //找到格子索引对应棋槽的序号
                    if (slotHeads[i] != null)
                        return captiveMap.get(slotHeads[i]).get(0); //通过序号对应棋头找到俘虏棋子的集合容器，返回其中任意一个棋子
                    else return null;
                }
            }
            return null;
        }

        /**
         * 绘制拘台和拘台上的棋子
         */
        public void drawSelf(ToriShogiRoom room) {
            for (int i = 0; i < slotHeads.length; i++) { //按照棋头排序顺序进行绘制
                if (slotHeads[i] != null) {
                    List<Chess> chessList = captiveMap.get(slotHeads[i]);
                    Chess indexChess = chessList.get(0); //取一个棋子作为绘制模板，添加的时候肯定会添加第一个，移除的时候棋头和chess列表都会移除
                    //给绘制模板设置属性用于绘制
                    indexChess.side = side;
                    indexChess.row = room.getRowByIndex(SLOT_INDEXES[i]);
                    indexChess.col = room.getColByIndex(SLOT_INDEXES[i]);
                    //棋子自身形象内部绘制
                    indexChess.drawSelf(room);
                    //相同类型棋子数量在外部绘制
                    if (side == 1) {
                        room.signList.add(new BadgeSign(SLOT_INDEXES[i], "x" + chessList.size(), 1, "#FFCC0000", "#00000000"));
                    }
                    else {
                        room.signList.add(new BadgeSign(SLOT_INDEXES[i], "x" + chessList.size(), 7, "#FFCC0000", "#00000000"));
                    }
                }
            }
        }

    }

    /**
     * 棋子基类
     */
    private abstract static class Chess {

        public int side; //棋子阵营，1：黑方，2：白方
        public int row; //棋子所在行数
        public int col;//棋子所在列数
        public boolean upgrade; //是否升变
        public boolean selected; //是否被选中

        public Chess(int side, int row, int col) {
            this.side = side;
            this.row = row;
            this.col = col;
            this.upgrade = false;
            this.selected = false;
        }

        /**
         * 获取棋子的纹饰名称
         */
        public abstract String getName();

        /**
         * 个性化移动限制算法
         */
        public abstract boolean isPosCanMove(int row, int col, ToriShogiRoom room);

        /**
         * 判断该位置是否可以打入
         */
        protected boolean isPosCanDrop(int row, int col, ToriShogiRoom room) {
            return generalDropLimit(row, col, room);
        }

        /**
         * 获取棋类标签
         */
        public String getOriginType() {
            return getClass().getSimpleName();
        }

        /**
         * 坐标与棋子之间有其它棋子阻碍
         */
        protected boolean hasPieceInBetween(int startX, int startY, int endX, int endY, int[][] board) {
            // 检查是否在同一行
            if (startX == endX) {
                for (int i = Math.min(startY, endY) + 1; i < Math.max(startY, endY); i++) {
                    if (board[startX][i] != 0) return true;
                }
            }
            // 检查是否在同一列
            else if (startY == endY) {
                for (int i = Math.min(startX, endX) + 1; i < Math.max(startX, endX); i++) {
                    if (board[i][startY] != 0) return true;
                }
            }
            // 检查是否在同一条对角线上
            else if (Math.abs(startX - endX) == Math.abs(startY - endY)) {
                int deltaX = startX < endX ? 1 : -1;
                int deltaY = startY < endY ? 1 : -1;

                for (int x = startX + deltaX, y = startY + deltaY; x != endX && y != endY; x += deltaX, y += deltaY) {
                    if (board[x][y] != 0) return true;
                }
            }
            // 如果不在同一行、同一列或同一条对角线上，直接返回 false
            return false;
        }

        /**
         * 尝试升变（移动前后都检查一遍）
         */
        public void checkUpgrade() {
            if (side == 1) {
                if (row >= WHITE_CAMP_ROW) {
                    upgrade = true;
                }
            }
            else {
                if (row <= BLACK_CAMP_ROW) {
                    upgrade = true;
                }
            }
        }

        //公共移动限制
        protected boolean generalMoveLimit(int row, int col, ToriShogiRoom room) {
            if (room.curGrids[row][col] % 10 == room.curGrids[this.row][this.col] % 10) return false; //不能移动到已有自己棋子的地方
            return true;
        }

        //公共的打入限制
        protected boolean generalDropLimit(int row, int col, ToriShogiRoom room) {
            if (room.curGrids[row][col] != 0) return false; //不能移动到已有棋子的地方
            return true;
        }

        /**
         * 获取可移动范围列表
         */
        public List<int[]> getCanMovedPos(ToriShogiRoom room) {
            List<int[]> canMovedPosList = new ArrayList<>();
            int startRow = 1;
            int startCol = 1;
            int endRow = room.curGrids.length - 1;
            int endCol = room.curGrids[0].length - 1;
            for (int i = startRow; i < endRow; i++) {
                for (int j = startCol; j < endCol; j++) {
                    if (isPosCanMove(i, j, room)) {
                        canMovedPosList.add(new int[]{i, j});
                    }
                }
            }
            return canMovedPosList;
        }

        /**
         * @param room
         * @return
         */
        private List<int[]> getCanDropPos(ToriShogiRoom room) {
            List<int[]> canDropPosList = new ArrayList<>();
            int startRow = 1;
            int startCol = 1;
            int endRow = room.curGrids.length - 1;
            int endCol = room.curGrids[0].length - 1;
            for (int i = startRow; i < endRow; i++) {
                for (int j = startCol; j < endCol; j++) {
                    if (isPosCanDrop(i, j, room)) {
                        canDropPosList.add(new int[]{i, j});
                    }
                }
            }
            return canDropPosList;
        }

        /**
         * 个性化绘制
         */
        public void drawSelf(ToriShogiRoom room) {
            if (side == 1) {
                room.curGrids[row][col] = selected ? 32 : 22;
                room.signList.add(new TitleSign((this.col + 0.5f) / room.curGrids[0].length, (this.row + 0.395f) / room.curGrids.length, 0, this.getName(), "#FF333333", 0.4f));
            }
            else {
                room.curGrids[row][col] = selected ? 31 : 21;
                room.signList.add(new TitleSign((this.col + 0.5f) / room.curGrids[0].length, (this.row + 0.505f) / room.curGrids.length, 0, this.getName(), "#FF333333", 0.4f));
            }
        }

        /**
         * 绘制可移动路径
         */
        public void drawCanMovedPath(ToriShogiRoom room) {
            List<int[]> canMovedPosList = getCanMovedPos(room); //获取该棋子可移动到的格子的坐标集合
            if (canMovedPosList.size() > 0) {
                for (int[] canMovedPos : canMovedPosList) {
                    room.signList.add(new TitleSign((canMovedPos[1] + 0.5f) / room.curGrids[0].length, (canMovedPos[0] + 0.5f) / room.curGrids.length, 0, "●", "#9988EE88", 0.333f));
                }
            }
        }

        /**
         * 绘制可打入位置
         */
        public void drawCanDropPos(ToriShogiRoom room) {
            List<int[]> canDropPosList = getCanDropPos(room); //获取该棋子可移动到的格子的坐标集合
            if (canDropPosList.size() > 0) {
                for (int[] canMovedPos : canDropPosList) {
                    room.signList.add(new TitleSign((canMovedPos[1] + 0.5f) / room.curGrids[0].length, (canMovedPos[0] + 0.5f) / room.curGrids.length, 0, "●", "#9988EE88", 0.333f));
                }
            }
        }

    }

    /**
     * 鵬
     */
    private static class Phoenix extends Chess {

        public static final String ORIGIN_TYPE = Phoenix.class.getSimpleName();

        public Phoenix(int side, int row, int col) {
            super(side, row, col);
        }

        @Override
        public String getName() {
            return "鵬";
        }

        @Override
        public String getOriginType() {
            return ORIGIN_TYPE;
        }

        @Override
        public boolean isPosCanMove(int row, int col, ToriShogiRoom room) {
            if (Math.abs(row - this.row) > 1 || Math.abs(col - this.col) > 1) return false;
            return generalMoveLimit(row, col, room);
        }

        @Override
        public void drawSelf(ToriShogiRoom room) {
            if (side == 1) {
                room.curGrids[row][col] = selected ? 32 : 22;
                room.signList.add(new TitleSign((this.col + 0.5f) / room.curGrids[0].length, (this.row + 0.395f) / room.curGrids.length, 0, this.getName(), "#FF222222", 0.45f));//王棋子稍微大一点,颜色也更黑一点

            }
            else {
                room.curGrids[row][col] = selected ? 31 : 21;
                room.signList.add(new TitleSign((this.col + 0.5f) / room.curGrids[0].length, (this.row + 0.505f) / room.curGrids.length, 0, this.getName(), "#FF222222", 0.45f));
            }
        }
    }

    /**
     * 鶴
     */
    private static class Crane extends Chess {

        public Crane(int side, int row, int col) {
            super(side, row, col);
        }

        @Override
        public String getName() {
            return "鶴";
        }

        @Override
        public boolean isPosCanMove(int row, int col, ToriShogiRoom room) {
            if (Math.abs(row - this.row) > 1 || Math.abs(col - this.col) > 1 || row == this.row) return false;
            return generalMoveLimit(row, col, room);
        }
    }

    /**
     * 雉
     */
    private static class Pheasant extends Chess {

        public Pheasant(int side, int row, int col) {
            super(side, row, col);
        }

        @Override
        public String getName() {
            return "雉";
        }

        @Override
        public boolean isPosCanMove(int row, int col, ToriShogiRoom room) {
            if (side == 1) {
                if (!(row == this.row + 2 && col == this.col) && !(row == this.row - 1 && col == this.col - 1) && !(row == this.row - 1 && col == this.col + 1))
                    return false;
            }
            else {
                if (!(row == this.row - 2 && col == this.col) && !(row == this.row + 1 && col == this.col - 1) && !(row == this.row + 1 && col == this.col + 1))
                    return false;
            }
            return generalMoveLimit(row, col, room);
        }
    }

    /**
     * 左鶉
     */
    private static class LeftQuail extends Chess {

        public LeftQuail(int side, int row, int col) {
            super(side, row, col);
        }

        @Override
        public String getName() {
            return "左鶉";
        }

        @Override
        public boolean isPosCanMove(int row, int col, ToriShogiRoom room) {
            if (side == 1) {
                //左下方只能走一格，前方和左前方走任意格
                if (col < this.col) {
                    if (col - this.col != row - this.row) return false; //只能斜向前走任意格
                    if (hasPieceInBetween(row, col, this.row, this.col, room.curGrids)) return false; //路径之间有障碍
                }
                if (col == this.col) {
                    if (row <= this.row) return false; //只能向前方走任意格
                    if (hasPieceInBetween(row, col, this.row, this.col, room.curGrids)) return false; //路径之间有障碍
                }
                if (col > this.col) {
                    if (col != this.col + 1 || row != this.row - 1) return false; //只能左前方走一格
                }
            }
            if (side == 2) {
                //左下方只能走一格，前方和右后方走任意格
                if (col < this.col) {
                    if (col != this.col - 1 || row != this.row + 1) return false; //只能左后方走一格
                }
                if (col == this.col) {
                    if (row >= this.row) return false; //只能向前方走任意格
                    if (hasPieceInBetween(row, col, this.row, this.col, room.curGrids)) return false; //路径之间有障碍
                }
                if (col > this.col) {
                    if (col - this.col != row - this.row) return false; //只能斜向后走任意格
                    if (hasPieceInBetween(row, col, this.row, this.col, room.curGrids)) return false; //路径之间有障碍
                }
            }
            return generalMoveLimit(row, col, room);
        }

        @Override
        public void drawSelf(ToriShogiRoom room) {
            if (side == 1) {
                room.curGrids[row][col] = selected ? 32 : 22;
                room.signList.add(new TitleSign((this.col + 0.70f) / room.curGrids[0].length, (this.row + 0.395f) / room.curGrids.length, 0, "左", "#FFCC3333", 0.180f)); //左右文字红色
                room.signList.add(new TitleSign((this.col + 0.45f) / room.curGrids[0].length, (this.row + 0.395f) / room.curGrids.length, 0, "鶉", "#FF333333", 0.385f)); //缩小一点
            }
            else {
                room.curGrids[row][col] = selected ? 31 : 21;
                room.signList.add(new TitleSign((this.col + 0.3f) / room.curGrids[0].length, (this.row + 0.505f) / room.curGrids.length, 0, "左", "#FFCC3333", 0.180f));
                room.signList.add(new TitleSign((this.col + 0.55f) / room.curGrids[0].length, (this.row + 0.505f) / room.curGrids.length, 0, "鶉", "#FF333333", 0.385f));
            }
        }
    }

    /**
     * 右鶉
     */
    private static class RightQuail extends Chess {
        public RightQuail(int side, int row, int col) {
            super(side, row, col);
        }

        @Override
        public String getName() {
            return "右鶉";
        }

        @Override
        public boolean isPosCanMove(int row, int col, ToriShogiRoom room) {
            if (side == 1) {
                //左下方只能走一格，前方和右前方走任意格
                if (col < this.col) {
                    if (col != this.col - 1 || row != this.row - 1) return false; //只能左前方走一格
                }
                if (col == this.col) {
                    if (row <= this.row) return false; //只能向前方走任意格
                    if (hasPieceInBetween(row, col, this.row, this.col, room.curGrids)) return false; //路径之间有障碍
                }
                if (col > this.col) {
                    if (col - this.col != this.row - row) return false; //只能斜向前走任意格
                    if (hasPieceInBetween(row, col, this.row, this.col, room.curGrids)) return false; //路径之间有障碍
                }
            }
            if (side == 2) {
                //右下方只能走一格，前方和左后方走任意格
                if (col > this.col) {
                    if (col != this.col + 1 || row != this.row + 1) return false; //只能右后方走一格
                }
                if (col == this.col) {
                    if (row >= this.row) return false; //只能向前方走任意格
                    if (hasPieceInBetween(row, col, this.row, this.col, room.curGrids)) return false; //路径之间有障碍
                }
                if (col < this.col) {
                    if (col - this.col != this.row - row) return false; //只能斜向前走任意格
                    if (hasPieceInBetween(row, col, this.row, this.col, room.curGrids)) return false; //路径之间有障碍
                }
            }
            return generalMoveLimit(row, col, room);
        }

        @Override
        public void drawSelf(ToriShogiRoom room) {
            if (side == 1) {
                room.curGrids[row][col] = selected ? 32 : 22;
                room.signList.add(new TitleSign((this.col + 0.3f) / room.curGrids[0].length, (this.row + 0.395f) / room.curGrids.length, 0, "右", "#FFCC3333", 0.180f)); //左右文字红色
                room.signList.add(new TitleSign((this.col + 0.55f) / room.curGrids[0].length, (this.row + 0.395f) / room.curGrids.length, 0, "鶉", "#FF333333", 0.385f)); //缩小一点
            }
            else {
                room.curGrids[row][col] = selected ? 31 : 21;
                room.signList.add(new TitleSign((this.col + 0.7f) / room.curGrids[0].length, (this.row + 0.505f) / room.curGrids.length, 0, "右", "#FFCC3333", 0.180f));
                room.signList.add(new TitleSign((this.col + 0.45f) / room.curGrids[0].length, (this.row + 0.505f) / room.curGrids.length, 0, "鶉", "#FF333333", 0.385f));
            }
        }
    }

    /**
     * 燕 - 雁
     */
    private static class Swallow extends Chess {

        public Swallow(int side, int row, int col) {
            super(side, row, col);
        }

        @Override
        public String getName() {
            if (upgrade) return "雁";
            else return "燕";
        }

        @Override
        public boolean isPosCanMove(int row, int col, ToriShogiRoom room) {
            //升级后"雁"的走法
            if (upgrade) {
                if (side == 1) {
                    boolean a = row == this.row + 2 && col == this.col - 2; //可移动到左前第二格
                    boolean b = row == this.row + 2 && col == this.col + 2; //可移动到右前第二格
                    boolean c = row == this.row - 2 && col == this.col; //可移动到正后第二格
                    if (!a && !b && !c) return false;
                }
                else {
                    boolean a = row == this.row - 2 && col == this.col - 2; //可移动到左前第二格
                    boolean b = row == this.row - 2 && col == this.col + 2; //可移动到右前第二格
                    boolean c = row == this.row + 2 && col == this.col; //可移动到正后第二格
                    if (!a && !b && !c) return false;
                }
                return generalMoveLimit(row, col, room);
            }
            //升级前"燕"的走法
            else {
                //只能直向前走一格
                if (col != this.col) return false;
                if (this.side == 1 && row != this.row + 1) return false;
                if (this.side == 2 && row != this.row - 1) return false;
                return generalMoveLimit(row, col, room);
            }
        }

        @Override
        protected boolean isPosCanDrop(int row, int col, ToriShogiRoom room) {
            if (side == 1 && row == 7) return false; //黑方的燕不能打入到白方底线
            if (side == 2 && row == 1) return false; //白方的燕不能打入到黑方的底线
            if (countOwnsSwallowsOnCol(col, room) > 1) return false; //本列己方燕的数量大于1时不可打入
            if (checkDropMate(row, col, room)) return false; //造成打步诘不可打入
            return generalDropLimit(row, col, room);
        }

        //判断打入到这里是否会造成打步诘
        private boolean checkDropMate(int row, int col, ToriShogiRoom room) {
            Chess chess = room.getChessByPos(side == 1 ? row + 1 : row - 1, col);
            if (chess != null && chess.side != side && chess instanceof Phoenix) { //打入燕后前方是敌方的鹏时，打步将
                if (checkMate(row, col, chess, room)) return true; //如果被将没法躲了视为打步诘
                else return false;
            }
            else return false;
        }

        //判断打入到这里是否会将死敌方的鹏
        private boolean checkMate(int row, int col, Chess enemyPhoenix, ToriShogiRoom room) {
            List<int[]> checkPoints = enemyPhoenix.getCanMovedPos(room); //获取敌方王所有的可走位置
            List<Chess> tempRemoveChessList = new ArrayList<>();//这些位置原本的棋子临时移除掉以免干扰判断
            for (int[] pos : checkPoints) {
                Chess tempChess = room.getChessByPos(pos[0], pos[1]);
                if (tempChess != null && tempChess.side == this.side) {//对方鹏可移动路径上的我方棋子临时移除
                    tempRemoveChessList.add(tempChess);
                    room.chessList.remove(tempChess);
                }
            }

            for (Chess chess : room.chessList) {
                if (chess.side == this.side) {
                    for (int[] pos : chess.getCanMovedPos(room)) {
                        checkPoints.removeIf(point -> Arrays.equals(point, pos)); //判断敌方鹏所有能走的位置，是否都能被我方棋子可移动路径覆盖，一旦有覆盖的这个点就移除掉，王不能走这里
                    }
                }
            }

            room.chessList.addAll(tempRemoveChessList);//把临时移除的棋子都还原回去
            return checkPoints.isEmpty(); //最后王没有地方可以走了就算被将死
        }

        //判断该列已有的燕数量
        private int countOwnsSwallowsOnCol(int col, ToriShogiRoom room) {
            int count = 0;
            for (Chess chess : room.chessList) {
                if (chess.side == side && chess.col == col && chess instanceof Swallow && !chess.upgrade) count++;
            }
            return count;
        }

        @Override
        public void drawSelf(ToriShogiRoom room) {
            //升级后"雁"的绘制
            if (upgrade) {
                if (side == 1) {
                    room.curGrids[row][col] = selected ? 32 : 22;
                    room.signList.add(new TitleSign((this.col + 0.5f) / room.curGrids[0].length, (this.row + 0.395f) / room.curGrids.length, 0, this.getName(), "#FFCC3333", 0.4f)); //升级棋文字颜色改成红色
                }
                else {
                    room.curGrids[row][col] = selected ? 31 : 21;
                    room.signList.add(new TitleSign((this.col + 0.5f) / room.curGrids[0].length, (this.row + 0.505f) / room.curGrids.length, 0, this.getName(), "#FFCC3333", 0.4f));
                }
            }
            //升级前"燕"的绘制
            else {
                super.drawSelf(room);
            }
        }
    }

    /**
     * 鷹 - 鵰
     */
    private static class Falcon extends Chess {

        public Falcon(int side, int row, int col) {
            super(side, row, col);
        }

        @Override
        public String getName() {
            if (upgrade) return "鵰";
            else return "鷹";
        }

        @Override
        public boolean isPosCanMove(int row, int col, ToriShogiRoom room) {
            //升级后"鵰"的走法
            if (upgrade) {
                if (row == this.row && Math.abs(col - this.col) != 1) return false; //左右直走只能走一格
                else if (row != this.row) { //非左右直走时
                    if (side == 1) {
                        if (col == this.col) { //竖向走
                            if (row > this.row && row != this.row + 1) return false; //只能前进一格
                            if (row < this.row && hasPieceInBetween(row, col, this.row, this.col, room.curGrids))
                                return false; //可以后退任意格子但是不能穿越其它棋子
                        }
                        else { //斜向走
                            if (Math.abs(col - this.col) != Math.abs(row - this.row)) return false; //只能45°角斜着走
                            if (hasPieceInBetween(row, col, this.row, this.col, room.curGrids)) return false;//不能穿越其它棋子
                            if (row < this.row && Math.abs(col - this.col) > 2) return false; //向后斜走最多只能两格
                        }
                    }
                    else {
                        if (col == this.col) {//竖向走
                            if (row < this.row && row != this.row - 1) return false; //只能前进一格
                            if (row > this.row && hasPieceInBetween(row, col, this.row, this.col, room.curGrids))
                                return false;//可以后退任意格子但是不能穿越其它棋子
                        }
                        else { //斜向走
                            if (Math.abs(col - this.col) != Math.abs(row - this.row)) return false; //只能45°角斜着走
                            if (hasPieceInBetween(row, col, this.row, this.col, room.curGrids)) return false;//不能穿越其它棋子
                            if (row > this.row && Math.abs(col - this.col) > 2) return false;//向后斜走最多只能两格
                        }
                    }
                }
                return generalMoveLimit(row, col, room);
            }
            //升级前"鷹"的走法
            else {
                if (Math.abs(row - this.row) > 1 || Math.abs(col - this.col) > 1) return false; //不能在3x3范围外移动
                if (side == 1) {
                    if (col == this.col && row == this.row - 1) return false; //不能向后移动
                }
                else {
                    if (col == this.col && row == this.row + 1) return false; //不能向后移动
                }
                return generalMoveLimit(row, col, room);
            }
        }

        @Override
        public void drawSelf(ToriShogiRoom room) {
            //升级后"鵰"的绘制
            if (upgrade) {
                if (side == 1) {
                    room.curGrids[row][col] = selected ? 32 : 22;
                    room.signList.add(new TitleSign((this.col + 0.5f) / room.curGrids[0].length, (this.row + 0.395f) / room.curGrids.length, 0, this.getName(), "#FFCC3333", 0.4f)); //升级棋文字颜色改成红色
                }
                else {
                    room.curGrids[row][col] = selected ? 31 : 21;
                    room.signList.add(new TitleSign((this.col + 0.5f) / room.curGrids[0].length, (this.row + 0.505f) / room.curGrids.length, 0, this.getName(), "#FFCC3333", 0.4f));
                }
            }
            //升级前"鷹"的绘制
            else {
                super.drawSelf(room);
            }
        }
    }

}
